﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using Eb;
using Es;

public enum LoginProcess
{
    VerifyRequest,
    VerifyResponse,
    ServiceRequest,
    ServiceResponse,
}

public class LoginInfo
{
    public string token;// 登陆id，guid
    public ulong acc_id;
    public string acc;
    public string pwd;
    public Dictionary<string, string> map_param;
    public LoginProcess login_process;
    public eLoginResult login_result;
    public IRpcCallerSession client_session;
}

public class DefUCenter : ComponentDef
{
    //---------------------------------------------------------------------
    public override void defAllProp(Dictionary<string, string> map_param)
    {
    }
}

public class LoginUCenter<T> : Component<T> where T : DefUCenter, new()
{
    //-------------------------------------------------------------------------
    Dictionary<string, LoginChannelProject<DefChannelProject>> mMapProject
        = new Dictionary<string, LoginChannelProject<DefChannelProject>>();// key=ProjectId
    Dictionary<string, LoginChannelService<DefChannelService>> mMapService
        = new Dictionary<string, LoginChannelService<DefChannelService>>();// key=NodeSId

    //-------------------------------------------------------------------------
    public string ZkNode4ProjectInfo { get; private set; }// "/UCenter/1.00.000/ProjectInfo"

    //-------------------------------------------------------------------------
    public override void init()
    {
        EbLog.Note("LoginUCenter.init()");

        EntityMgr.getDefaultEventPublisher().addHandler(Entity);

        defNodeRpcMethod<ClientLoginRequest>(
            (ushort)_eUCenterMethodType.client2loginLogin, client2loginLogin);
        defNodeRpcMethod(
    (ushort)_eUCenterMethodType.client2loginHeartbeat, client2loginHeartbeat);
        defNodeRpcMethod<bool, LoginData>(
            (ushort)_eUCenterMethodType.project2loginOnLogin, _project2ucenterRecvData);

        var cfg = EsEngine.Instance.Config;
        var settings = EsEngine.Instance.Settings;

        ZkNode4ProjectInfo = "/" + settings.ProjectName + "/" + cfg.Version + "/" + _eUCenterZkNodeName.ProjectInfo.ToString();
        var zk_client = EsEngine.Instance.ZkClient;
        zk_client.syncCreate(ZkNode4ProjectInfo, "", ZK_CONST.ZOO_DEFAULT_NODE);
        zk_client.subscribeChildChanges(ZkNode4ProjectInfo, _onZkNode4ProjectListChildChanged);

        var co_supersocket = EsEngine.Instance.CoSuperSocket;
        co_supersocket.OnSessionCreate += _onSuperSocketSessionCreate;
        co_supersocket.OnSessionDestroy += _onSuperSocketSessionDestroy;
    }

    //-------------------------------------------------------------------------
    public override void release()
    {
        EbLog.Note("LoginUCenter.release()");
    }

    //-------------------------------------------------------------------------
    public override void update(float elapsed_tm)
    {
    }

    //-------------------------------------------------------------------------
    public override void handleEvent(object sender, EntityEvent e)
    {
    }

    //-------------------------------------------------------------------------
    public void addChannelService(IComponent co)
    {
        LoginChannelService<DefChannelService> co_service = (LoginChannelService<DefChannelService>)co;
        mMapService[co_service.NodeMQ] = co_service;
    }

    //-------------------------------------------------------------------------
    public void removeChannelService(IComponent co)
    {
        LoginChannelService<DefChannelService> co_service = (LoginChannelService<DefChannelService>)co;
        mMapService.Remove(co_service.NodeMQ);
    }

    //-------------------------------------------------------------------------
    // 响应登陆请求
    public void client2loginLogin(ClientLoginRequest request)
    {
        Dictionary<string, string> map_param = new Dictionary<string, string>();
        map_param["ProjectName"] = request.project_name;
        map_param["ChannelName"] = request.channel_name;
        map_param["Version"] = request.version_name;

        // todo: 根据配置文件解析出来的key规则，拼接key
        string key = request.project_name;
        if (!string.IsNullOrEmpty(request.version_name))
        {
            key += "_";
            key += request.version_name;
        }

        EbLog.Note("登陆验证step 1 of 6: 接收到Client登陆请求, Key=" + key + " Acc=" + request.acc);

        // 查找key对应的Project，并投递登陆请求
        LoginChannelProject<DefChannelProject> co = null;
        if (mMapProject.TryGetValue(key, out co))
        {
            EbLog.Note("登陆验证step 2 of 6: 将Client登陆请求分发给对应Project, Key=" + key + " Acc=" + request.acc);
            co.client2ucenterLogin(request.acc, request.pwd, map_param, EntityMgr.LastRpcCallerSession);
        }
        else
        {
            EbLog.Error("失败，为找到Key对应的Project！ Key=" + key);
        }
    }

    //-------------------------------------------------------------------------
    public void client2loginHeartbeat()
    {
    }

    //-------------------------------------------------------------------------
    // Service->UCenter，登陆响应
    void _project2ucenterRecvData(bool result, LoginData login_data)
    {
        //EbLog.Note("LoginUCenter._project2ucenterRecvData() Service验证完成! ");

        login_data.service_result = result;
        LoginChannelService<DefChannelService> co;
        if (mMapService.TryGetValue(login_data.service_mq, out co))
        {
            co.project2ucenterRecvData(login_data);
        }
        else
        {
            EbLog.Error("LoginUCenter._project2ucenterRecvData() not found service_mq=" + login_data.service_mq);
        }
    }

    //-------------------------------------------------------------------------
    void _onZkNode4ProjectListChildChanged(int result, string data, string[] chdn, Dictionary<string, object> param)
    {
        if (result != 0) return;

        List<string> list_project_node_remote = null;
        if (chdn != null) list_project_node_remote = chdn.ToList();
        else list_project_node_remote = new List<string>();
        List<string> list_project_node_local = mMapProject.Keys.ToList<string>();
        IEnumerable<string> list_add = list_project_node_remote.Except(list_project_node_local);
        IEnumerable<string> list_del = list_project_node_local.Except(list_project_node_remote);

        // 被移除的ChannelProject
        foreach (var i in list_del)
        {
            LoginChannelProject<DefChannelProject> co = null;
            if (mMapProject.TryGetValue(i, out co))
            {
                EntityMgr.destroyEntity(co.Entity);
                mMapProject.Remove(i);
            }
        }

        // 新增的ChannelProject
        foreach (var i in list_add)
        {
            Dictionary<string, object> cache_data = new Dictionary<string, object>();
            cache_data["ProjectId"] = i;
            Entity et_project = EntityMgr.createEntity<EtChannelProject>(cache_data, Entity);
            var co = et_project.getComponent<LoginChannelProject<DefChannelProject>>();
            mMapProject[i] = co;
        }
    }

    //-------------------------------------------------------------------------
    void _onSuperSocketSessionCreate(IRpcCallerSession s)
    {
    }

    //-------------------------------------------------------------------------
    void _onSuperSocketSessionDestroy(IRpcCallerSession s, SessionCloseReason reason)
    {
    }
}
